package org.yu.register.machine;

import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag;
import net.minecraft.network.Connection;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.ClientGamePacketListener;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.ItemStackHandler;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.yu.ItemData;
import org.yu.api.util.ITickable;
import org.yu.register.BlockRegister;
import org.yu.register.CapabilityRegister;
import org.yu.register.ItemRegister;
import org.yu.register.MachineRegistry;

import javax.annotation.Nonnull;

public class LlandudnoBlockEntity extends BlockEntity implements ITickable {

    //格子分配：0-8药草,9输出
    protected final ItemStackHandler itemStackHandler=new ItemStackHandler(10){
        @Override
        public boolean isItemValid(int slot, @Nonnull ItemStack stack) {
            return switch (slot) {
                case 0,1,2,3,4,5,6,7,8 -> ItemData.has(stack.getItem());
                default -> false;
            };
        }

        @Override
        protected void onContentsChanged(int slot) {
            if(slot<9&start) {
                resetProcess();
            }
            setChanged();
            if(level !=null)
            level.sendBlockUpdated(getBlockPos(),getBlockState(),getBlockState(),3);
        }
        @Override
        public void deserializeNBT(CompoundTag nbt)
        {
            setSize(10);//修复之前储存的slot数量问题
            ListTag tagList = nbt.getList("Items", Tag.TAG_COMPOUND);
            for (int i = 0; i < tagList.size(); i++)
            {
                CompoundTag itemTags = tagList.getCompound(i);
                int slot = itemTags.getInt("Slot");

                if (slot >= 0 && slot < stacks.size())
                {
                    stacks.set(slot, ItemStack.of(itemTags));
                }
            }
            onLoad();
        }
    };
    protected boolean start=false;
    protected int recipeTime=0;
    public LlandudnoBlockEntity(BlockEntityType<?> pType, BlockPos pWorldPosition, BlockState pBlockState) {
        super(pType, pWorldPosition, pBlockState);
    }

    @Nonnull
    @Override
    public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) {
        if (cap==CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)
            return LazyOptional.of(()->itemStackHandler).cast();
        return LazyOptional.empty();
    }

    @Override
    public void tick() {
        if(level!=null&&!level.isClientSide) {
            boolean lit = checkFire();
            if (!lit & start) {
                resetProcess();
                return;
            }
            if (lit) {
                if (!start && itemStackHandler.getStackInSlot(9).isEmpty())
                    for (int i = 0; i < 9; i++) {
                        if (!itemStackHandler.getStackInSlot(i).isEmpty()) {
                            start = true;
                            break;
                        }
                    }
                if (start) recipeTime++;
                if (recipeTime == 100) {
                    resetProcess();
                    onSuccess();
                }
                level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), 3);
            }
        }
    }

    protected void resetProcess(){
        start=false;
        recipeTime=0;
    }
    protected void onSuccess(){
        var danYao=makeDanYao();
        setResult(danYao);
    }
    protected ItemStack makeDanYao(){
        var danYao=new ItemStack(ItemRegister.danYao);
        danYao.getCapability(CapabilityRegister.MIXED_ITEM)
                .ifPresent(mixedCapability -> {
                    for(int i=0;i<9;i++){
                        var item=itemStackHandler.getStackInSlot(i);
                        if(!item.isEmpty()){
                          var data= ItemData.getAttribute(item.getItem());
                          if(data!=null) {
                              data.forEach((attribute, level) -> {
                                  mixedCapability.putAttribute(attribute.name, level * item.getCount());
                              });
                              mixedCapability.putMixed(item.getItem(), item.getCount());
                              itemStackHandler.setStackInSlot(i,ItemStack.EMPTY);
                          }
                        }
                    }
                });
        return danYao;
    }
    protected void setResult(ItemStack stack){
        var item=itemStackHandler.getStackInSlot(9);
        if(!item.isEmpty()&&level!=null){
            var pos=getBlockPos();
            ItemEntity itemEntity=new ItemEntity(level,pos.getX(),pos.getY()+1,pos.getZ(),item);
            level.addFreshEntity(itemEntity);
        }
        itemStackHandler.setStackInSlot(9,stack);
    }

    protected boolean checkFire(){
        if(level==null)return false;
        BlockState state=level.getBlockState(getBlockPos().below());
        if(state.is(MachineRegistry.stove.get()))
            return state.getValue(StoveBlock.LIT);
        return false;
    }

    @Override
    protected void saveAdditional(@Nonnull CompoundTag pTag) {
        pTag.putBoolean("Start",start);
        pTag.putInt("RecipeTime",recipeTime);
        pTag.put("Items", itemStackHandler.serializeNBT());
        super.saveAdditional(pTag);
    }

    @Override
    public void load(CompoundTag pTag) {
        start=pTag.getBoolean("Start");
        recipeTime=pTag.getInt("RecipeTime");
        itemStackHandler.deserializeNBT(pTag.getCompound("Items"));
        super.load(pTag);
    }
    @Nullable
    @Override
    public Packet<ClientGamePacketListener> getUpdatePacket() {
        return ClientboundBlockEntityDataPacket.create(this);
    }

    @Override
    public void handleUpdateTag(CompoundTag pTag) {
        super.handleUpdateTag(pTag);
        recipeTime=pTag.getInt("RecipeTime");
        itemStackHandler.deserializeNBT(pTag.getCompound("Items"));
    }

    @NotNull
    @Override
    public CompoundTag getUpdateTag() {
        var pTag=super.getUpdateTag();
        pTag.putInt("RecipeTime",recipeTime);
        pTag.put("Items",itemStackHandler.serializeNBT());
        return pTag;
    }

    @SuppressWarnings("all")
    @Override
    public void onDataPacket(Connection net, ClientboundBlockEntityDataPacket pkt) {
        this.handleUpdateTag(pkt.getTag());
    }
}
